package com.newx.limit.aop;

import com.newx.limit.annotation.NewxLimit;
import com.newx.limit.condition.LimitAspectCondition;
import com.newx.limit.entity.Limiter;
import com.newx.limit.handler.exeption.NewxLimitException;
import com.newx.limit.manage.LimiterManager;
import lombok.Setter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author yxl
 * @date 2024/7/5 0005 18:08
 */
@Aspect
@EnableAspectJAutoProxy(proxyTargetClass = true) //使用CGLIB代理
@Conditional(LimitAspectCondition.class)
@Component
public class NewxLimitAspect {

    @Setter(onMethod_ = @Autowired)
    private LimiterManager limiterManager;

    @Pointcut("@annotation(com.newx.limit.annotation.NewxLimit)")
    private void check() {

    }

    @Before("check()")
    public void before(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        NewxLimit newxLimit = method.getAnnotation(NewxLimit.class);
        if(newxLimit != null){
            Limiter limiter = Limiter.builder()
                    .limitNum(newxLimit.limitNum())
                    .key(newxLimit.key())
                    .seconds(newxLimit.timeout())
                    .msg(newxLimit.msg())
                    .build();
            if(!limiterManager.tryAccess(limiter)){
                throw new NewxLimitException(limiter.getMsg());
            }
        }
    }
}
